guint keycode,
GdkModifierType state,
GtkWidget *widget);
-static void gtk_calendar_key_controller_focus (GtkEventControllerKey *controller,
- GdkCrossingMode mode,
- GdkNotifyType detail,
+static void gtk_calendar_key_controller_focus (GtkEventController *controller,
+ GtkCrossingDirection direction,
GtkWidget *widget);
static void gtk_calendar_state_flags_changed (GtkWidget *widget,
GtkStateFlags previous_state);
g_signal_connect (controller, "key-pressed",
G_CALLBACK (gtk_calendar_key_controller_key_pressed),
calendar);
- g_signal_connect (controller, "focus-in",
- G_CALLBACK (gtk_calendar_key_controller_focus),
- calendar);
- g_signal_connect (controller, "focus-out",
+ g_signal_connect (controller, "focus-change",
G_CALLBACK (gtk_calendar_key_controller_focus),
calendar);
gtk_widget_add_controller (GTK_WIDGET (calendar), controller);
}
static void
-gtk_calendar_key_controller_focus (GtkEventControllerKey *key,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkWidget *widget)
+gtk_calendar_key_controller_focus (GtkEventController *controller,
+ GtkCrossingDirection direction,
+ GtkWidget *widget)
{
GtkCalendar *calendar = GTK_CALENDAR (widget);
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
return FALSE;
}
-static gboolean
-text_focus_out (GtkEntryCompletion *completion)
+static void
+text_focus_change (GtkEntryCompletion *completion,
+ GtkCrossingDirection direction)
{
- if (gtk_widget_get_mapped (completion->priv->popup_window))
- return FALSE;
-
- return accept_completion_callback (completion);
+ if (direction == GTK_CROSSING_OUT &&
+ !gtk_widget_get_mapped (completion->priv->popup_window))
+ accept_completion_callback (completion);
}
static void
controller = priv->entry_key_controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "key-pressed",
G_CALLBACK (gtk_entry_completion_key_pressed), completion);
- g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (text_focus_out), completion);
+ g_signal_connect_swapped (controller, "focus-change", G_CALLBACK (text_focus_change), completion);
gtk_widget_add_controller (GTK_WIDGET (text), controller);
completion->priv->changed_id =
GTK_EVENT_SEQUENCE_DENIED
} GtkEventSequenceState;
+typedef enum {
+ GTK_CROSSING_FOCUS,
+ GTK_CROSSING_POINTER
+} GtkCrossingType;
+
+typedef enum {
+ GTK_CROSSING_IN,
+ GTK_CROSSING_OUT
+} GtkCrossingDirection;
+
/**
* GtkPanDirection:
* @GTK_PAN_DIRECTION_LEFT: panned towards the left
return FALSE;
}
+static void
+gtk_event_controller_handle_crossing_default (GtkEventController *self,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+}
+
static void
gtk_event_controller_set_property (GObject *object,
guint prop_id,
klass->unset_widget = gtk_event_controller_unset_widget;
klass->filter_event = gtk_event_controller_filter_event_default;
klass->handle_event = gtk_event_controller_handle_event_default;
+ klass->handle_crossing = gtk_event_controller_handle_crossing_default;
object_class->finalize = gtk_event_controller_finalize;
object_class->set_property = gtk_event_controller_set_property;
return retval;
}
+/**
+ * gtk_event_controller_handle_crossing:
+ * @controller: a #GtkEventController
+ * @crossing: a #GtkCrossingData
+ * @x: event position in widget coordinates
+ * @y: event position in widget coordinates
+ *
+ * Feeds a crossing event into @controller, so it can be interpreted
+ * and the controller actions triggered.
+ **/
+void
+gtk_event_controller_handle_crossing (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+ GtkEventControllerClass *controller_class;
+
+ g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
+ g_return_if_fail (crossing != NULL);
+
+ controller_class = GTK_EVENT_CONTROLLER_GET_CLASS (controller);
+
+ g_object_ref (controller);
+ controller_class->handle_crossing (controller, crossing, x, y);
+ g_object_unref (controller);
+}
+
/**
* gtk_event_controller_get_widget:
* @controller: a #GtkEventController
g_free (priv->name);
priv->name = g_strdup (name);
}
+
+static GtkCrossingData *
+gtk_crossing_data_copy (GtkCrossingData *crossing)
+{
+ GtkCrossingData *copy;
+
+ copy = g_new (GtkCrossingData, 1);
+
+ copy->type = crossing->type;
+ copy->direction = crossing->direction;
+
+ if (crossing->old_target)
+ copy->old_target = g_object_ref (crossing->old_target);
+ if (crossing->new_target)
+ copy->new_target = g_object_ref (crossing->new_target);
+
+ return copy;
+}
+
+static void
+gtk_crossing_data_free (GtkCrossingData *crossing)
+{
+ g_clear_object (&crossing->old_target);
+ g_clear_object (&crossing->new_target);
+
+ g_free (crossing);
+}
+
+G_DEFINE_BOXED_TYPE (GtkCrossingData, gtk_crossing_data,
+ gtk_crossing_data_copy, gtk_crossing_data_free)
#define GTK_EVENT_CONTROLLER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_EVENT_CONTROLLER, GtkEventControllerClass))
+typedef struct _GtkCrossingData GtkCrossingData;
+
+/**
+ * GtkCrossingData:
+ * @type: the type of crossing event
+ * @direction: whether this is a focus-in or focus-out event
+ * @mode: the crossing mode
+ * @old_target: the old target
+ * @new_target: the new target
+ *
+ * The struct that is passed to gtk_event_controller_handle_crossing()
+ * and is also passed to #GtkEventControllerKey::focus-change.
+ *
+ * The @old_target and @new_target fields are set to the old or new
+ * focus or hover location.
+ */
+struct _GtkCrossingData {
+ GtkCrossingType type;
+ GtkCrossingDirection direction;
+ GdkCrossingMode mode;
+ GtkWidget *old_target;
+ GtkWidget *new_target;
+};
+
+#define GTK_TYPE_CROSSING_DATA (gtk_crossing_data_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+GType gtk_crossing_data_get_type (void) G_GNUC_CONST;
+
+
GDK_AVAILABLE_IN_ALL
GType gtk_event_controller_get_type (void) G_GNUC_CONST;
double x,
double y);
GDK_AVAILABLE_IN_ALL
+void gtk_event_controller_handle_crossing (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y);
+GDK_AVAILABLE_IN_ALL
void gtk_event_controller_reset (GtkEventController *controller);
GDK_AVAILABLE_IN_ALL
#include "gtkbindings.h"
#include "gtkenums.h"
#include "gtkmain.h"
+#include "gtktypebuiltins.h"
#include <gdk/gdk.h>
GdkModifierType state;
const GdkEvent *current_event;
+ const GtkCrossingData *current_crossing;
guint is_focus : 1;
guint contains_focus : 1;
KEY_RELEASED,
MODIFIERS,
IM_UPDATE,
- FOCUS_IN,
- FOCUS_OUT,
+ FOCUS_CHANGE,
N_SIGNALS
};
G_OBJECT_CLASS (gtk_event_controller_key_parent_class)->finalize (object);
}
-static void
-update_focus (GtkEventControllerKey *key,
- gboolean focus_in,
- GdkNotifyType detail)
-{
- gboolean is_focus;
- gboolean contains_focus;
-
- switch (detail)
- {
- case GDK_NOTIFY_VIRTUAL:
- case GDK_NOTIFY_NONLINEAR_VIRTUAL:
- is_focus = FALSE;
- contains_focus = focus_in;
- break;
- case GDK_NOTIFY_ANCESTOR:
- case GDK_NOTIFY_NONLINEAR:
- is_focus = focus_in;
- contains_focus = is_focus;
- break;
- case GDK_NOTIFY_INFERIOR:
- is_focus = focus_in;
- contains_focus = TRUE;
- break;
- case GDK_NOTIFY_UNKNOWN:
- default:
- g_warning ("Unknown focus change detail");
- return;
- }
-
- g_object_freeze_notify (G_OBJECT (key));
- if (key->is_focus != is_focus)
- {
- key->is_focus = is_focus;
- g_object_notify (G_OBJECT (key), "is-focus");
- if (key->im_context)
- {
- if (focus_in)
- gtk_im_context_focus_in (key->im_context);
- else
- gtk_im_context_focus_out (key->im_context);
- }
- }
- if (key->contains_focus != contains_focus)
- {
- key->contains_focus = contains_focus;
- g_object_notify (G_OBJECT (key), "contains-focus");
- }
- g_object_thaw_notify (G_OBJECT (key));
-}
-
static gboolean
gtk_event_controller_key_handle_event (GtkEventController *controller,
const GdkEvent *event,
guint keyval;
gboolean handled = FALSE;
- if (event_type == GDK_FOCUS_CHANGE)
- {
- gboolean focus_in;
- GdkCrossingMode mode;
- GdkNotifyType detail;
-
- gdk_event_get_focus_in (event, &focus_in);
- gdk_event_get_crossing_mode (event, &mode);
- gdk_event_get_crossing_detail (event, &detail);
-
- update_focus (key, focus_in, detail);
-
- key->current_event = event;
-
- if (focus_in)
- g_signal_emit (controller, signals[FOCUS_IN], 0, mode, detail);
- else
- g_signal_emit (controller, signals[FOCUS_OUT], 0, mode, detail);
-
- key->current_event = NULL;
-
- return FALSE;
- }
-
if (event_type != GDK_KEY_PRESS && event_type != GDK_KEY_RELEASE)
return FALSE;
return handled;
}
+static void
+update_focus (GtkEventController *controller,
+ const GtkCrossingData *crossing)
+{
+ GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (controller);
+ GtkWidget *widget = gtk_event_controller_get_widget (controller);
+ gboolean is_focus = FALSE;
+ gboolean contains_focus = FALSE;
+
+ if (crossing->direction == GTK_CROSSING_IN)
+ {
+ if (crossing->new_target == widget)
+ is_focus = TRUE;
+ if (crossing->new_target != NULL)
+ contains_focus = TRUE;
+ }
+
+ g_object_freeze_notify (G_OBJECT (key));
+ if (key->is_focus != is_focus)
+ {
+ key->is_focus = is_focus;
+ g_object_notify (G_OBJECT (key), "is-focus");
+ if (key->im_context)
+ {
+ if (is_focus)
+ gtk_im_context_focus_in (key->im_context);
+ else
+ gtk_im_context_focus_out (key->im_context);
+ }
+ }
+ if (key->contains_focus != contains_focus)
+ {
+ key->contains_focus = contains_focus;
+ g_object_notify (G_OBJECT (key), "contains-focus");
+ }
+ g_object_thaw_notify (G_OBJECT (key));
+}
+
+static void
+gtk_event_controller_key_handle_crossing (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+ GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (controller);
+
+ if (crossing->type != GTK_CROSSING_FOCUS)
+ return;
+
+ key->current_crossing = crossing;
+
+ update_focus (controller, crossing);
+
+ g_signal_emit (controller, signals[FOCUS_CHANGE], 0, crossing->direction);
+
+ key->current_crossing = NULL;
+}
+
static void
gtk_event_controller_key_get_property (GObject *object,
guint prop_id,
object_class->finalize = gtk_event_controller_key_finalize;
object_class->get_property = gtk_event_controller_key_get_property;
controller_class->handle_event = gtk_event_controller_key_handle_event;
+ controller_class->handle_crossing = gtk_event_controller_key_handle_crossing;
/**
* GtkEventControllerKey:is-focus:
/**
* GtkEventControllerKey::im-update:
- * @controller: the object which received the signal.
+ * @controller: the object which received the signal
*
* This signal is emitted whenever the input method context filters away a
* keypress and prevents the @controller receiving it. See
G_TYPE_NONE, 0);
/**
- * GtkEventControllerKey::focus-in:
- * @controller: the object which received the signal.
- * @mode: crossing mode indicating what caused this change
- * @detail: detail indication where the focus is coming from
+ * GtkEventControllerKey::focus-change:
+ * @controller: the object which received the signal
+ * @direction: the direction of this crossing event
*
- * This signal is emitted whenever the widget controlled
- * by the @controller or one of its descendants) is given
- * the keyboard focus.
- */
- signals[FOCUS_IN] =
- g_signal_new (I_("focus-in"),
- GTK_TYPE_EVENT_CONTROLLER_KEY,
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 2,
- GDK_TYPE_CROSSING_MODE,
- GDK_TYPE_NOTIFY_TYPE);
-
- /**
- * GtkEventControllerKey::focus-out:
- * @controller: the object which received the signal.
- * @mode: crossing mode indicating what caused this change
- * @detail: detail indication where the focus is going
+ * This signal is emitted whenever the focus change from or
+ * to a widget that is a descendant of the widget to which
+ * @controller is attached.
*
- * This signal is emitted whenever the widget controlled
- * by the @controller (or one of its descendants) loses
- * the keyboard focus.
+ * Handlers for this signal can use
+ * gtk_event_controller_key_get_focus_origin() and
+ * gtk_event_controller_key_get_focus_target() to find
+ * the old and new focus locations.
*/
- signals[FOCUS_OUT] =
- g_signal_new (I_("focus-out"),
+ signals[FOCUS_CHANGE] =
+ g_signal_new (I_("focus-change"),
GTK_TYPE_EVENT_CONTROLLER_KEY,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
NULL,
- G_TYPE_NONE,
- 2,
- GDK_TYPE_CROSSING_MODE,
- GDK_TYPE_NOTIFY_TYPE);
+ G_TYPE_NONE, 1,
+ GTK_TYPE_CROSSING_DIRECTION);
}
static void
* Returns the widget that was holding focus before.
*
* This function can only be used in handlers for the
- * #GtkEventControllerKey::focus-in and
- * #GtkEventControllerKey::focus-out signals.
+ * #GtkEventControllerKey::focus-changed signal.
*
* Returns: (transfer none): the previous focus
*/
GtkWidget *
gtk_event_controller_key_get_focus_origin (GtkEventControllerKey *controller)
{
- gboolean focus_in;
- GtkWidget *origin;
-
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
- g_return_val_if_fail (controller->current_event != NULL, NULL);
- g_return_val_if_fail (gdk_event_get_event_type (controller->current_event) == GDK_FOCUS_CHANGE, NULL);
-
- gdk_event_get_focus_in (controller->current_event, &focus_in);
+ g_return_val_if_fail (controller->current_crossing != NULL, NULL);
- if (focus_in)
- origin = (GtkWidget *)gdk_event_get_related_target (controller->current_event);
- else
- origin = (GtkWidget *)gdk_event_get_target (controller->current_event);
-
- return origin;
+ return controller->current_crossing->old_target;
}
/**
* Returns the widget that will be holding focus afterwards.
*
* This function can only be used in handlers for the
- * #GtkEventControllerKey::focus-in and
- * #GtkEventControllerKey::focus-out signals.
+ * #GtkEventControllerKey::focus-changed signal.
*
* Returns: (transfer none): the next focus
*/
GtkWidget *
gtk_event_controller_key_get_focus_target (GtkEventControllerKey *controller)
{
- gboolean focus_in;
-
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
- g_return_val_if_fail (controller->current_event != NULL, NULL);
- g_return_val_if_fail (gdk_event_get_event_type (controller->current_event) == GDK_FOCUS_CHANGE, NULL);
+ g_return_val_if_fail (controller->current_crossing != NULL, NULL);
- gdk_event_get_focus_in (controller->current_event, &focus_in);
-
- if (focus_in)
- return (GtkWidget *)gdk_event_get_target (controller->current_event);
- else
- return (GtkWidget *)gdk_event_get_related_target (controller->current_event);
+ return controller->current_crossing->new_target;
}
/**
double y);
void (* reset) (GtkEventController *controller);
+ void (* handle_crossing) (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y);
+
/*<private>*/
/* Tells whether the event is filtered out, %TRUE makes
}
static void
-chooser_entry_focus_out (GtkEventControllerKey *key_controller,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkFileChooserEntry *chooser_entry)
+chooser_entry_focus_change (GtkEventController *controller,
+ GtkCrossingDirection direction,
+ GtkFileChooserEntry *chooser_entry)
{
- set_complete_on_load (chooser_entry, FALSE);
+ if (direction == GTK_CROSSING_OUT)
+ set_complete_on_load (chooser_entry, FALSE);
}
static void
G_CALLBACK (gtk_file_chooser_entry_tab_handler),
chooser_entry);
g_signal_connect (controller,
- "focus-out", G_CALLBACK (chooser_entry_focus_out),
+ "focus-change", G_CALLBACK (chooser_entry_focus_change),
chooser_entry);
gtk_widget_add_controller (GTK_WIDGET (chooser_entry), controller);
}
static void
-focus_in_cb (GtkEventController *controller,
- GdkCrossingMode mode,
- GdkNotifyType type,
- gpointer data)
+focus_change_cb (GtkEventController *controller,
+ GtkCrossingDirection direction,
+ gpointer data)
{
GtkWidget *target;
GtkWidget *popover;
- target = gtk_event_controller_get_widget (controller);
- popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
+ if (direction == GTK_CROSSING_IN)
+ {
+ target = gtk_event_controller_get_widget (controller);
+ popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
- if (popover)
- gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), target);
+ if (popover)
+ gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), target);
+ }
}
static void
gtk_widget_add_controller (GTK_WIDGET (self), controller);
controller = gtk_event_controller_key_new ();
- g_signal_connect (controller, "focus-in", G_CALLBACK (focus_in_cb), NULL);
+ g_signal_connect (controller, "focus-change", G_CALLBACK (focus_change_cb), NULL);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
gesture = gtk_gesture_click_new ();
present_popup (popover);
}
-
-static void
-gtk_popover_focus_in (GtkWidget *widget)
-{
-}
-
-static void
-gtk_popover_focus_out (GtkWidget *widget)
-{
-}
-
static void
close_menu (GtkPopover *popover)
{
priv->has_arrow = TRUE;
controller = gtk_event_controller_key_new ();
- g_signal_connect_swapped (controller, "focus-in", G_CALLBACK (gtk_popover_focus_in), popover);
- g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (gtk_popover_focus_out), popover);
g_signal_connect_swapped (controller, "key-pressed", G_CALLBACK (gtk_popover_key_pressed), popover);
gtk_widget_add_controller (GTK_WIDGET (popover), controller);
}
static void
-focus_out (GtkEventControllerKey *controller,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkPopoverMenu *menu)
+focus_change (GtkEventController *controller,
+ GtkCrossingDirection direction,
+ GtkPopoverMenu *menu)
{
GtkWidget *new_focus = gtk_root_get_focus (gtk_widget_get_root (GTK_WIDGET (menu)));
- if (!gtk_event_controller_key_contains_focus (controller) &&
+ if (direction == GTK_CROSSING_OUT &&
+ !gtk_event_controller_key_contains_focus (GTK_EVENT_CONTROLLER_KEY (controller)) &&
new_focus != NULL)
{
if (menu->parent_menu &&
gtk_widget_add_css_class (GTK_WIDGET (popover), "menu");
controller = gtk_event_controller_key_new ();
- g_signal_connect (controller, "focus-out", G_CALLBACK (focus_out), popover);
+ g_signal_connect (controller, "focus-change", G_CALLBACK (focus_change), popover);
gtk_widget_add_controller (GTK_WIDGET (popover), controller);
controller = gtk_event_controller_motion_new ();
}
static void
-key_controller_focus_out (GtkEventControllerKey *key,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkSpinButton *spin_button)
+key_controller_focus_change (GtkEventController *controller,
+ GtkCrossingDirection direction,
+ GtkSpinButton *spin_button)
{
GtkSpinButtonPrivate *priv = gtk_spin_button_get_instance_private (spin_button);
- if (gtk_editable_get_editable (GTK_EDITABLE (priv->entry)))
+ if (direction == GTK_CROSSING_OUT &&
+ gtk_editable_get_editable (GTK_EDITABLE (priv->entry)))
gtk_spin_button_update (spin_button);
}
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "key-released",
G_CALLBACK (key_controller_key_released), spin_button);
- g_signal_connect (controller, "focus-out",
- G_CALLBACK (key_controller_focus_out), spin_button);
+ g_signal_connect (controller, "focus-change",
+ G_CALLBACK (key_controller_focus_change), spin_button);
gtk_widget_add_controller (GTK_WIDGET (spin_button), controller);
}
int baseline);
static void gtk_text_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot);
-static void gtk_text_focus_in (GtkWidget *widget);
-static void gtk_text_focus_out (GtkWidget *widget);
+static void gtk_text_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction);
static gboolean gtk_text_grab_focus (GtkWidget *widget);
static void gtk_text_css_changed (GtkWidget *widget,
GtkCssStyleChange *change);
G_CALLBACK (gtk_text_key_controller_key_pressed), self);
g_signal_connect_swapped (priv->key_controller, "im-update",
G_CALLBACK (gtk_text_schedule_im_reset), self);
- g_signal_connect_swapped (priv->key_controller, "focus-in",
- G_CALLBACK (gtk_text_focus_in), self);
- g_signal_connect_swapped (priv->key_controller, "focus-out",
- G_CALLBACK (gtk_text_focus_out), self);
+ g_signal_connect_swapped (priv->key_controller, "focus-change",
+ G_CALLBACK (gtk_text_focus_change), self);
gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (priv->key_controller),
priv->im_context);
gtk_widget_add_controller (GTK_WIDGET (self), priv->key_controller);
}
static void
-gtk_text_focus_in (GtkWidget *widget)
+gtk_text_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction)
{
GtkText *self = GTK_TEXT (widget);
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GdkKeymap *keymap;
- gtk_widget_queue_draw (widget);
-
- keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
-
- if (priv->editable)
+ if (direction == GTK_CROSSING_IN)
{
- gtk_text_schedule_im_reset (self);
- gtk_im_context_focus_in (priv->im_context);
- }
+ gtk_widget_queue_draw (widget);
- g_signal_connect (keymap, "direction-changed",
- G_CALLBACK (keymap_direction_changed), self);
+ keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
- gtk_text_reset_blink_time (self);
- gtk_text_check_cursor_blink (self);
-}
+ if (priv->editable)
+ {
+ gtk_text_schedule_im_reset (self);
+ gtk_im_context_focus_in (priv->im_context);
+ }
-static void
-gtk_text_focus_out (GtkWidget *widget)
-{
- GtkText *self = GTK_TEXT (widget);
- GtkTextPrivate *priv = gtk_text_get_instance_private (self);
- GdkKeymap *keymap;
+ g_signal_connect (keymap, "direction-changed",
+ G_CALLBACK (keymap_direction_changed), self);
- gtk_text_selection_bubble_popup_unset (self);
+ gtk_text_reset_blink_time (self);
+ gtk_text_check_cursor_blink (self);
+ }
+ else
+ {
+ gtk_text_selection_bubble_popup_unset (self);
- if (priv->text_handle)
- _gtk_text_handle_set_mode (priv->text_handle,
- GTK_TEXT_HANDLE_MODE_NONE);
+ if (priv->text_handle)
+ _gtk_text_handle_set_mode (priv->text_handle,
+ GTK_TEXT_HANDLE_MODE_NONE);
- gtk_widget_queue_draw (widget);
+ gtk_widget_queue_draw (widget);
- keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
+ keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
- if (priv->editable)
- {
- gtk_text_schedule_im_reset (self);
- gtk_im_context_focus_out (priv->im_context);
- }
+ if (priv->editable)
+ {
+ gtk_text_schedule_im_reset (self);
+ gtk_im_context_focus_out (priv->im_context);
+ }
- gtk_text_check_cursor_blink (self);
+ gtk_text_check_cursor_blink (self);
- g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, self);
+ g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, self);
+ }
}
static gboolean
static void gtk_text_view_key_controller_im_update (GtkEventControllerKey *controller,
GtkTextView *text_view);
-static void gtk_text_view_focus_in (GtkWidget *widget);
-static void gtk_text_view_focus_out (GtkWidget *widget);
+static void gtk_text_view_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction);
static void gtk_text_view_motion (GtkEventController *controller,
double x,
double y,
g_signal_connect (priv->key_controller, "im-update",
G_CALLBACK (gtk_text_view_key_controller_im_update),
widget);
- g_signal_connect_swapped (priv->key_controller, "focus-in",
- G_CALLBACK (gtk_text_view_focus_in),
- widget);
- g_signal_connect_swapped (priv->key_controller, "focus-out",
- G_CALLBACK (gtk_text_view_focus_out),
+ g_signal_connect_swapped (priv->key_controller, "focus-change",
+ G_CALLBACK (gtk_text_view_focus_change),
widget);
gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (priv->key_controller),
priv->im_context);
}
static void
-gtk_text_view_focus_in (GtkWidget *widget)
+gtk_text_view_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction)
{
- GtkTextView *text_view;
- GtkTextViewPrivate *priv;
-
- text_view = GTK_TEXT_VIEW (widget);
- priv = text_view->priv;
-
- gtk_widget_queue_draw (widget);
-
- DV(g_print (G_STRLOC": focus_in\n"));
-
- gtk_text_view_reset_blink_time (text_view);
+ GtkTextView *text_view = GTK_TEXT_VIEW (widget);
+ GtkTextViewPrivate *priv = text_view->priv;
- if (cursor_visible (text_view) && priv->layout)
+ if (direction == GTK_CROSSING_IN)
{
- gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
- gtk_text_view_check_cursor_blink (text_view);
- }
+ gtk_widget_queue_draw (widget);
- g_signal_connect (gdk_display_get_keymap (gtk_widget_get_display (widget)),
- "direction-changed",
- G_CALLBACK (keymap_direction_changed), text_view);
- gtk_text_view_check_keymap_direction (text_view);
+ DV(g_print (G_STRLOC": focus_in\n"));
- if (priv->editable)
- {
- priv->need_im_reset = TRUE;
- gtk_im_context_focus_in (priv->im_context);
- }
-}
+ gtk_text_view_reset_blink_time (text_view);
-static void
-gtk_text_view_focus_out (GtkWidget *widget)
-{
- GtkTextView *text_view;
- GtkTextViewPrivate *priv;
+ if (cursor_visible (text_view) && priv->layout)
+ {
+ gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
+ gtk_text_view_check_cursor_blink (text_view);
+ }
- text_view = GTK_TEXT_VIEW (widget);
- priv = text_view->priv;
+ g_signal_connect (gdk_display_get_keymap (gtk_widget_get_display (widget)),
+ "direction-changed",
+ G_CALLBACK (keymap_direction_changed), text_view);
+ gtk_text_view_check_keymap_direction (text_view);
- gtk_text_view_end_selection_drag (text_view);
+ if (priv->editable)
+ {
+ priv->need_im_reset = TRUE;
+ gtk_im_context_focus_in (priv->im_context);
+ }
+ }
+ else
+ {
+ gtk_text_view_end_selection_drag (text_view);
- gtk_widget_queue_draw (widget);
+ gtk_widget_queue_draw (widget);
- DV(g_print (G_STRLOC": focus_out\n"));
+ DV(g_print (G_STRLOC": focus_out\n"));
- if (cursor_visible (text_view) && priv->layout)
- {
- gtk_text_view_check_cursor_blink (text_view);
- gtk_text_layout_set_cursor_visible (priv->layout, FALSE);
- }
+ if (cursor_visible (text_view) && priv->layout)
+ {
+ gtk_text_view_check_cursor_blink (text_view);
+ gtk_text_layout_set_cursor_visible (priv->layout, FALSE);
+ }
- g_signal_handlers_disconnect_by_func (gdk_display_get_keymap (gtk_widget_get_display (widget)),
- keymap_direction_changed,
- text_view);
- gtk_text_view_selection_bubble_popup_unset (text_view);
+ g_signal_handlers_disconnect_by_func (gdk_display_get_keymap (gtk_widget_get_display (widget)),
+ keymap_direction_changed,
+ text_view);
+ gtk_text_view_selection_bubble_popup_unset (text_view);
- if (priv->text_handle)
- _gtk_text_handle_set_mode (priv->text_handle,
- GTK_TEXT_HANDLE_MODE_NONE);
+ if (priv->text_handle)
+ _gtk_text_handle_set_mode (priv->text_handle,
+ GTK_TEXT_HANDLE_MODE_NONE);
- if (priv->editable)
- {
- priv->need_im_reset = TRUE;
- gtk_im_context_focus_out (priv->im_context);
+ if (priv->editable)
+ {
+ priv->need_im_reset = TRUE;
+ gtk_im_context_focus_out (priv->im_context);
+ }
}
}
guint keycode,
GdkModifierType state,
GtkTreeView *tree_view);
-static void gtk_tree_view_key_controller_focus_out (GtkEventControllerKey *key,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkTreeView *tree_view);
+static void gtk_tree_view_key_controller_focus_change (GtkEventController *key,
+ GtkCrossingDirection direction,
+ GtkTreeView *tree_view);
static gint gtk_tree_view_focus (GtkWidget *widget,
GtkDirectionType direction);
G_CALLBACK (gtk_tree_view_key_controller_key_pressed), tree_view);
g_signal_connect (controller, "key-released",
G_CALLBACK (gtk_tree_view_key_controller_key_released), tree_view);
- g_signal_connect (controller, "focus-out",
- G_CALLBACK (gtk_tree_view_key_controller_focus_out), tree_view);
+ g_signal_connect (controller, "focus-change",
+ G_CALLBACK (gtk_tree_view_key_controller_focus_change), tree_view);
gtk_widget_add_controller (GTK_WIDGET (tree_view), controller);
}
}
static void
-gtk_tree_view_key_controller_focus_out (GtkEventControllerKey *key,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkTreeView *tree_view)
+gtk_tree_view_key_controller_focus_change (GtkEventController *key,
+ GtkCrossingDirection direction,
+ GtkTreeView *tree_view)
{
- gboolean is_focus, contains_focus;
-
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
- g_object_get (key,
- "is-focus", &is_focus,
- "contains-focus", &contains_focus,
- NULL);
+ if (direction == GTK_CROSSING_OUT)
+ {
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
- if (tree_view->search_popover && !gtk_event_controller_key_contains_focus (key))
- gtk_tree_view_search_popover_hide (tree_view->search_popover, tree_view,
- gtk_get_current_event_device ());
+ if (tree_view->search_popover &&
+ !gtk_event_controller_key_contains_focus (GTK_EVENT_CONTROLLER_KEY (key)))
+ gtk_tree_view_search_popover_hide (tree_view->search_popover, tree_view,
+ gtk_get_current_event_device ());
+ }
}
/* Incremental Reflow
static void
focus_in (GtkEventControllerKey *controller,
- GdkCrossingMode mode,
- GdkNotifyType detail,
+ GtkCrossingDirection direction,
GtkTreeViewColumn *column)
{
- _gtk_tree_view_set_focus_column (GTK_TREE_VIEW (column->priv->tree_view), column);
+ if (direction == GTK_CROSSING_IN)
+ _gtk_tree_view_set_focus_column (GTK_TREE_VIEW (column->priv->tree_view), column);
}
/* Button handling code
gtk_widget_add_controller (priv->button, controller);
controller = gtk_event_controller_key_new ();
- g_signal_connect (controller, "focus-in", G_CALLBACK (focus_in), tree_column);
+ g_signal_connect (controller, "focus-change", G_CALLBACK (focus_in), tree_column);
gtk_widget_add_controller (priv->button, controller);
priv->frame = gtk_frame_new (NULL);
return handled;
}
+void
+gtk_widget_handle_crossing (GtkWidget *widget,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+ GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+ GList *l;
+
+ g_object_ref (widget);
+
+ for (l = priv->event_controllers; l; l = l->next)
+ {
+ GtkEventController *controller = l->data;
+
+ gtk_event_controller_handle_crossing (controller, crossing, x, y);
+ }
+
+ g_object_unref (widget);
+}
+
static gboolean
translate_event_coordinates (GdkEvent *event,
double *x,
double x,
double y,
GtkPropagationPhase phase);
+void gtk_widget_handle_crossing (GtkWidget *widget,
+ const GtkCrossingData *crossing,
+ double x,
+ double y);
guint gtk_widget_add_surface_transform_changed_callback (GtkWidget *widget,
int height,
int baseline);
static gboolean gtk_window_close_request (GtkWindow *window);
-static void gtk_window_focus_in (GtkWidget *widget);
-static void gtk_window_focus_out (GtkWidget *widget);
+static void gtk_window_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction);
static gboolean gtk_window_key_pressed (GtkWidget *widget,
guint keyval,
guint keycode,
priv->key_controller = gtk_event_controller_key_new ();
gtk_event_controller_set_propagation_phase (priv->key_controller, GTK_PHASE_CAPTURE);
- g_signal_connect_swapped (priv->key_controller, "focus-in",
- G_CALLBACK (gtk_window_focus_in), window);
- g_signal_connect_swapped (priv->key_controller, "focus-out",
- G_CALLBACK (gtk_window_focus_out), window);
+ g_signal_connect_swapped (priv->key_controller, "focus-change",
+ G_CALLBACK (gtk_window_focus_change), window);
g_signal_connect_swapped (priv->key_controller, "key-pressed",
G_CALLBACK (gtk_window_key_pressed), window);
g_signal_connect_swapped (priv->key_controller, "key-released",
}
static void
-gtk_window_focus_in (GtkWidget *widget)
+gtk_window_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction)
{
GtkWindow *window = GTK_WINDOW (widget);
- /* It appears spurious focus in events can occur when
- * the window is hidden. So we'll just check to see if
- * the window is visible before actually handling the
- * event
- */
- if (gtk_widget_get_visible (widget))
+ if (direction == GTK_CROSSING_IN)
{
- _gtk_window_set_is_active (window, TRUE);
+ /* It appears spurious focus in events can occur when
+ * the window is hidden. So we'll just check to see if
+ * the window is visible before actually handling the
+ * event
+ */
+ if (gtk_widget_get_visible (widget))
+ {
+ _gtk_window_set_is_active (window, TRUE);
- if (gtk_window_has_mnemonic_modifier_pressed (window))
- _gtk_window_schedule_mnemonics_visible (window);
+ if (gtk_window_has_mnemonic_modifier_pressed (window))
+ _gtk_window_schedule_mnemonics_visible (window);
+ }
}
-}
-
-static void
-gtk_window_focus_out (GtkWidget *widget)
-{
- GtkWindow *window = GTK_WINDOW (widget);
-
- _gtk_window_set_is_active (window, FALSE);
+ else
+ {
+ _gtk_window_set_is_active (window, FALSE);
- /* set the mnemonic-visible property to false */
- gtk_window_set_mnemonics_visible (window, FALSE);
+ /* set the mnemonic-visible property to false */
+ gtk_window_set_mnemonics_visible (window, FALSE);
+ }
}
static void
gtk_window_set_focus (GTK_WINDOW (widget), NULL);
}
+static void
+synthesize_focus_change_events (GtkWindow *window,
+ GtkWidget *old_focus,
+ GtkWidget *new_focus)
+{
+ GtkCrossingData crossing;
+ GtkWidget *widget, *focus_child;
+ GList *list, *l;
+ GtkStateFlags flags;
+
+ flags = GTK_STATE_FLAG_FOCUSED;
+ if (gtk_window_get_focus_visible (GTK_WINDOW (window)))
+ flags |= GTK_STATE_FLAG_FOCUS_VISIBLE;
+
+ crossing.type = GTK_CROSSING_FOCUS;
+ crossing.mode = GDK_CROSSING_NORMAL;
+ crossing.old_target = old_focus;
+ crossing.new_target = new_focus;
+
+ crossing.direction = GTK_CROSSING_OUT;
+
+ widget = old_focus;
+ while (widget)
+ {
+ gtk_widget_handle_crossing (widget, &crossing, 0, 0);
+ gtk_widget_unset_state_flags (widget, flags);
+ gtk_widget_set_focus_child (widget, NULL);
+ widget = gtk_widget_get_parent (widget);
+ }
+
+ list = NULL;
+ widget = new_focus;
+ while (widget)
+ {
+ list = g_list_prepend (list, widget);
+ widget = gtk_widget_get_parent (widget);
+ }
+
+ crossing.direction = GTK_CROSSING_IN;
+
+ for (l = list; l; l = l->next)
+ {
+ widget = l->data;
+ if (l->next)
+ focus_child = l->next->data;
+ else
+ focus_child = NULL;
+ gtk_widget_handle_crossing (widget, &crossing, 0, 0);
+ gtk_widget_set_state_flags (widget, flags, FALSE);
+ gtk_widget_set_focus_child (widget, focus_child);
+ }
+
+ g_list_free (list);
+}
+
/**
* gtk_window_set_focus:
* @window: a #GtkWindow
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
GtkWidget *old_focus = NULL;
- GdkSeat *seat;
- GdkDevice *device;
- GdkEvent *event;
g_return_if_fail (GTK_IS_WINDOW (window));
old_focus = g_object_ref (priv->focus_widget);
g_set_object (&priv->focus_widget, NULL);
- seat = gdk_display_get_default_seat (gtk_widget_get_display (GTK_WIDGET (window)));
- device = gdk_seat_get_keyboard (seat);
+ if (old_focus)
+ gtk_widget_set_has_focus (old_focus, FALSE);
- event = gdk_event_focus_new (priv->surface, device, device, TRUE);
+ synthesize_focus_change_events (window, old_focus, focus);
- gtk_synthesize_crossing_events (GTK_ROOT (window), old_focus, focus, event, GDK_CROSSING_NORMAL);
-
- gdk_event_unref (event);
+ if (focus)
+ gtk_widget_set_has_focus (focus, TRUE);
g_set_object (&priv->focus_widget, focus);